/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.

This file is part of Quake III Arena source code.

Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.

Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Quake III Arena source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
 */
// snd_local.h -- private sound definations


#include "../qcommon/q_shared.h"
#include "../qcommon/qcommon.h"
#include "snd_public.h"

#define	PAINTBUFFER_SIZE		4096					// this is in samples

#define SND_CHUNK_SIZE			1024					// samples
#define SND_CHUNK_SIZE_FLOAT	(SND_CHUNK_SIZE/2)		// floats
#define SND_CHUNK_SIZE_BYTE		(SND_CHUNK_SIZE*2)		// floats

typedef struct {
    int left; // the final values will be clamped to +/- 0x00ffff00 and shifted down
    int right;
} portable_samplepair_t;

typedef struct adpcm_state {
    short sample; /* Previous output value */
    char index; /* Index into stepsize table */
} adpcm_state_t;

typedef struct sndBuffer_s {
    short sndChunk[SND_CHUNK_SIZE];
    struct sndBuffer_s *next;
    int size;
    adpcm_state_t adpcm;
} sndBuffer;

typedef struct sfx_s {
    sndBuffer *soundData;
    qboolean defaultSound; // couldn't be loaded, so use buzz
    qboolean inMemory; // not in Memory
    qboolean soundCompressed; // not in Memory
    int soundCompressionMethod;
    int soundLength;
    char soundName[MAX_QPATH];
    int lastTimeUsed;
    struct sfx_s *next;
} sfx_t;

typedef struct {
    int channels;
    int samples; // mono samples in buffer
    int submission_chunk; // don't mix less than this #
    int samplebits;
    int speed;
    byte *buffer;
} dma_t;

#define START_SAMPLE_IMMEDIATE	0x7fffffff

#define MAX_DOPPLER_SCALE 50.0f //arbitrary

typedef struct loopSound_s {
    vec3_t origin;
    vec3_t velocity;
    sfx_t *sfx;
    int mergeFrame;
    qboolean active;
    qboolean kill;
    qboolean doppler;
    float dopplerScale;
    float oldDopplerScale;
    int framenum;
} loopSound_t;

typedef struct {
    int allocTime;
    int startSample; // START_SAMPLE_IMMEDIATE = set immediately on next mix
    int entnum; // to allow overriding a specific sound
    int entchannel; // to allow overriding a specific sound
    int leftvol; // 0-255 volume after spatialization
    int rightvol; // 0-255 volume after spatialization
    int master_vol; // 0-255 volume before spatialization
    float dopplerScale;
    float oldDopplerScale;
    vec3_t origin; // only use if fixed_origin is set
    qboolean fixed_origin; // use origin instead of fetching entnum's origin
    sfx_t *thesfx; // sfx structure
    qboolean doppler;
} channel_t;


#define	WAV_FORMAT_PCM		1

typedef struct {
    int format;
    int rate;
    int width;
    int channels;
    int samples;
    int dataofs; // chunk starts this many bytes from file start
} wavinfo_t;

// Interface between Q3 sound "api" and the sound backend

typedef struct {
    void (*Shutdown)(void);
    void (*StartSound)(vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx);
    void (*StartLocalSound)(sfxHandle_t sfx, int channelNum);
    void (*StartBackgroundTrack)(const char *intro, const char *loop);
    void (*StopBackgroundTrack)(void);
    void (*RawSamples)(int stream, int samples, int rate, int width, int channels, const byte *data, float volume);
    void (*StopAllSounds)(void);
    void (*ClearLoopingSounds)(qboolean killall);
    void (*AddLoopingSound)(int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx);
    void (*AddRealLoopingSound)(int entityNum, const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx);
    void (*StopLoopingSound)(int entityNum);
    void (*Respatialize)(int entityNum, const vec3_t origin, vec3_t axis[3], int inwater);
    void (*UpdateEntityPosition)(int entityNum, const vec3_t origin);
    void (*Update)(void);
    void (*DisableSounds)(void);
    void (*BeginRegistration)(void);
    sfxHandle_t(*RegisterSound)(const char *sample, qboolean compressed);
    void (*ClearSoundBuffer)(void);
    void (*SoundInfo)(void);
    void (*SoundList)(void);
#ifdef USE_VOIP
    void (*StartCapture)(void);
    int (*AvailableCaptureSamples)(void);
    void (*Capture)(int samples, byte * data);
    void (*StopCapture)(void);
    void (*MasterGain)(float gain);
#endif
} soundInterface_t;


/*
====================================================================

  SYSTEM SPECIFIC FUNCTIONS

====================================================================
 */

// initializes cycling through a DMA buffer and returns information on it
qboolean SNDDMA_Init(void);

// gets the current DMA position
int SNDDMA_GetDMAPos(void);

// shutdown the DMA xfer.
void SNDDMA_Shutdown(void);

void SNDDMA_BeginPainting(void);

void SNDDMA_Submit(void);

//====================================================================

#define	MAX_CHANNELS			96

extern channel_t s_channels[MAX_CHANNELS];
extern channel_t loop_channels[MAX_CHANNELS];
extern int numLoopChannels;

extern int s_paintedtime;
extern vec3_t listener_forward;
extern vec3_t listener_right;
extern vec3_t listener_up;
extern dma_t dma;

#define	MAX_RAW_SAMPLES	16384
#define MAX_RAW_STREAMS 128
extern portable_samplepair_t s_rawsamples[MAX_RAW_STREAMS][MAX_RAW_SAMPLES];
extern int s_rawend[MAX_RAW_STREAMS];

extern cvar_t *s_volume;
extern cvar_t *s_musicVolume;
extern cvar_t *s_muted;
extern cvar_t *s_doppler;

extern cvar_t *s_testsound;

qboolean S_LoadSound(sfx_t *sfx);

void SND_free(sndBuffer *v);
sndBuffer* SND_malloc(void);
void SND_setup(void);

void S_PaintChannels(int endtime);

void S_memoryLoad(sfx_t *sfx);

// spatializes a channel
void S_Spatialize(channel_t *ch);

// adpcm functions
int S_AdpcmMemoryNeeded(const wavinfo_t *info);
void S_AdpcmEncodeSound(sfx_t *sfx, short *samples);
void S_AdpcmGetSamples(sndBuffer *chunk, short *to);

// wavelet function

#define SENTINEL_MULAW_ZERO_RUN 127
#define SENTINEL_MULAW_FOUR_BIT_RUN 126

void S_FreeOldestSound(void);

#define	NXStream byte

void encodeWavelet(sfx_t *sfx, short *packets);
void decodeWavelet(sndBuffer *stream, short *packets);

void encodeMuLaw(sfx_t *sfx, short *packets);
extern short mulawToShort[256];

extern short *sfxScratchBuffer;
extern sfx_t *sfxScratchPointer;
extern int sfxScratchIndex;

qboolean S_Base_Init(soundInterface_t *si);

// OpenAL stuff

typedef enum {
    SRCPRI_AMBIENT = 0, // Ambient sound effects
    SRCPRI_ENTITY, // Entity sound effects
    SRCPRI_ONESHOT, // One-shot sounds
    SRCPRI_LOCAL, // Local sounds
    SRCPRI_STREAM // Streams (music, cutscenes)
} alSrcPriority_t;

typedef int srcHandle_t;

qboolean S_AL_Init(soundInterface_t *si);
